<?php

/**
 * Pulls data from arrays stored in php files.
 *
 * Data from a config or even a Zend_Db_Table may be pushed into this, as long
 * as the columns are the same and are converted to an array beforehand.
 *
 * @author     Mon Zafra <monzee at gmail>
 * @copyright  (c)2009 Mon Zafra
 * @category   Mz
 * @package    modules
 * @subpackage admin
 * @license    http://mz-project.googlecode.com/svn/trunk/LICENSE    MIT License
 * @version    SVN: $Id: Array.php 47 2009-05-28 17:56:56Z monzee $
 */
class Admin_Model_Acl_Array implements Admin_Model_Acl_Adapter
{
    protected $_users;
    protected $_roles;
    protected $_permissions;
    protected $_resources;
    protected $_userRoles;
    protected $_roleTree;
    
    public $info = 'You can find the user, roles, user x role, role x role and
permissions data in <code>APPLICATION_PATH/modules/admin/data/array/</code>.';

    /**
     * constructor
     *
     * possible option keys (case-sensitive):
     * - users       array
     * - roles       array
     * - permissions array
     * - resources   array
     * - userRoles   array
     * - roleTree    array
     *
     * @param array|Zend_Config $options
     */
    public function __construct($options = array())
    {
        if (!empty($options)) {
            $this->setOptions($options);
        }
    }

    /**
     * Set adapter options.
     * 
     * @param array|Zend_Config $options
     * @return Admin_Model_Acl_Array
     * @throws Admin_Mode_Acl_Exception If $options is not an array/Zend_Config
     */
    public function setOptions($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        } else if (!is_array($options)) {
            throw new Admin_Model_Acl_Exception('Invalid options passed to acl model adapter');
        }
        foreach ($options as $opt => $val) {
            $setter = 'set' . $opt;
            $this->$setter($val);
        }
        return $this;
    }

    /**
     * all users
     * @return array
     */
    public function getAllUsers()
    {
        if (null === $this->_users) {
            $this->_users = include dirname(__FILE__) . '/../../data/users.php';
        }
        return $this->_users;
    }

    /**
     * all possible roles
     * @return array
     */
    public function getAllRoles()
    {
        if (null === $this->_roles) {
            $this->_roles = include dirname(__FILE__) . '/../../data/roles.php';
        }
        return $this->_roles;
    }

    /**
     * role x resource(id, priv) map. either allowed or denied
     * @return array
     */
    public function getAllPermissions()
    {
        if (null === $this->_permissions) {
            $this->_permissions = include dirname(__FILE__) . '/../../data/permissions.php';
        }
        return $this->_permissions;
    }

    /**
     * all roles of all users
     * a method by that name already
     * @return array
     */
    public function getAllUserRoles()
    {
        if (null === $this->_userRoles) {
            $this->_userRoles = include dirname(__FILE__) . '/../../data/user_roles.php';
        }
        return $this->_userRoles;
    }

    /**
     * role parent => child map
     * @return array
     */
    public function getRoleTree()
    {
        if (null === $this->_roleTree) {
            $this->_roleTree = include dirname(__FILE__) . '/../../data/role_graph.php';
        }
        return $this->_roleTree;
    }

    /**
     * Capture set* calls
     *
     * @param string $method
     * @param array  $args
     * @return Admin_Models_Acl_Array
     * @throws BadMethodCallException If the first 3 letters != 'set' (case-
     * sensitive).
     */
    public function __call($method, $args)
    {
        if ('set' == substr($method, 0, 3)) {
            $prop = '_' . strtolower($method[3]) . substr($method, 4);
            if (property_exists($this, $prop)) {
                $this->$prop = $args[0];
            }
        } else {
            throw new BadMethodCallException('No such method (' . $method . ').');
        }
        return $this;
    }

    /**
     *
     * @param string $username
     * @return array User row
     * @throws Admin_Model_Acl_Exception if there is no such user in the store
     */
    public function getUserByUserName($username)
    {
        $users = $this->getAllUsers();
        foreach ($users as $user) {
            if ($username == $user['username']) {
                return $user;
            }
        }
        throw new Admin_Model_Acl_Exception('User not found.');
    }

    /**
     *
     * @param mixed $roleId
     * @return array Role row
     * @throws Admin_Model_Acl_Exception if there is no such role.
     */
    public function getRoleById($roleId)
    {
        $roles = $this->getAllRoles();
        foreach ($roles as $role) {
            if ($roleId == $role['id']) {
                return $role;
            }
        }
        throw new Admin_Model_Acl_Exception('Role not found.');
    }

    /**
     *
     * @param array $user User row
     * @return array Array of role details
     */
    public function getUserRoles($user)
    {
        $userRoles = $this->getAllUserRoles();
        $roles = array();
        foreach ($userRoles as $row) {
            if ($user['id'] == $row['user_id']) {
                $roles[] = $this->getRoleById($row['role_id']);
            }
        }
        return $roles;
    }

    /**
     *
     * @param mixed $role Role row
     * @return array Array of role rows
     */
    public function getParentRoles($role)
    {
        $roleTree = $this->getRoleTree();
        $parentRoles = array();
        foreach ($roleTree as $rel) {
            if ($role['id'] == $rel['child_id']) {
                $parentRoles[] = $this->getRoleById($rel['parent_id']);
            }
        }
        return $parentRoles;
    }

    /**
     *
     * @param mixed $resId Resource id to search
     * @return array Array of rows(roleId, resourceId, priv, isAllowed)
     */
    public function getRulesByResourceId($resId)
    {
        $permissions = $this->getAllPermissions();
        $rules = array();
        foreach ($permissions as $rule) {
            if ($resId == $rule['resource_id']) {
                $rules[] = $rule;
            }
        }
        return $rules;
    }

}